﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;

using Microsoft.Crm.Sdk.Messages;

namespace Fes.Xrm.Methods
{
    public class MetodosFes
    {
        public static IOrganizationService Servicio;

        // Constructor que recibe los parámetros usados para autenticar el Plugin o la Aplicacion Tercera
        public MetodosFes(IOrganizationService serv)
        {
            Servicio = serv;
        }

        #region # Método utilizado para conocer si el atributo se encuentra en el diccionario de datos
        public static Boolean ExisteAtributo(string name, Entity entity)
        {
            Boolean existe = false;
            foreach (var EntidadRes in entity.Attributes)
            {
                if (EntidadRes.Key == name) { existe = true; }
            }
            return existe;
        }
        #endregion

        #region # Método de Recuperación de Metadatos para Opciones de Lista
        public static string RecuperaOpcionListaTexto(string vEntityLogicalName, string vLogicalNameAtributo, OptionSetValue ValorDeComparacion)
        {
            string sReturn = string.Empty;
            string OptionText = "";
            RetrieveAttributeRequest request = new RetrieveAttributeRequest();
            request.EntityLogicalName = vEntityLogicalName;// "";
            request.LogicalName = vLogicalNameAtributo;
            RetrieveAttributeResponse response = (RetrieveAttributeResponse)Servicio.Execute(request);

            PicklistAttributeMetadata picklist = (PicklistAttributeMetadata)response.AttributeMetadata;

            foreach (OptionMetadata option in picklist.OptionSet.Options)
            {
                if (option.Value == ValorDeComparacion.Value)
                {
                    OptionText = option.Label.UserLocalizedLabel.Label;
                    break;
                }
            }
            return sReturn = OptionText;
        }
        #endregion

        #region # Método para Desactivar Registros en CRM
        public static void DesactivarRegistro(bool Desac, string nombreent, Guid Idreg, Int32 Razon)
        {
            var cols = new ColumnSet(new[] { "statecode", "statuscode" });

            //Se verifica si está activo
            var ResEnt = Servicio.Retrieve(nombreent, Idreg, cols);

            if (ResEnt != null)
            {
                //StateCode = 0 Activo
                //StateCode = 1 Inactivo
                SetStateRequest setStateRequest = new SetStateRequest();

                setStateRequest.EntityMoniker = new EntityReference(nombreent, Idreg);

                if (Desac) // Desactivar
                    setStateRequest.State = new OptionSetValue(1);
                else      // Activar
                    setStateRequest.State = new OptionSetValue(0);

                // Colocar la razon para el estado
                setStateRequest.Status = new OptionSetValue(Razon);

                Servicio.Execute(setStateRequest);
            }
        }
        #endregion

        # region # Método de Recuperación de datos en CRM 1 Filtro (Equal)
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1)
        {
            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);


            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }

        #endregion

        # region # Método de Recuperación de datos en CRM 2 filtros (AND) (Equal)
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2)
        {
            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 3 Filtros (AND) (Equal)
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2, string AtributoFiltro3, string ValorFiltro3)
        {
            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);

            FilterExpression filtrosubhijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro3, ConditionOperator.Equal, ValorFiltro3);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 4 Filtros (AND) (Equal)
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2, string AtributoFiltro3, string ValorFiltro3, string AtributoFiltro4, string ValorFiltro4)
        {
            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);
            filtrohijo.AddCondition(AtributoFiltro3, ConditionOperator.Equal, ValorFiltro3);
            filtrohijo.AddCondition(AtributoFiltro4, ConditionOperator.Equal, ValorFiltro4);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 2 filtros (AND) (Equal) Order By Atributo Ascending
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2, string AtriOrd)
        {

            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);

            // Orden por el Atributo Recibido
            consulta.AddOrder(AtriOrd, OrderType.Descending);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 2 filtros  (Equal) (AND) (NotEqual)
        public static EntityCollection RecuperacionMultipleNot(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2)
        {

            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.NotEqual, ValorFiltro2);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 3 filtros  (Equal) (AND) (NotEqual)
        public static EntityCollection RecuperacionMultipleNot(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2, string AtributoFiltro3, string ValorFiltro3)
        {

            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);
            filtrohijo.AddCondition(AtributoFiltro3, ConditionOperator.NotEqual, ValorFiltro3);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        /* *****************  METODOS GFA ********************************/

        #region *** Metodo que genera digito verificador por medio del algoritmo de Luhn
        public static string DigitoVerificadorLuhn(string numero)
        {
            var sum = 0;
            var alt = true;
            var digits = numero.ToCharArray();
            for (int i = digits.Length - 1; i >= 0; i--)
            {
                var curDigit = (digits[i] - 48);
                if (alt)
                {
                    curDigit *= 2;
                    if (curDigit > 9)
                        curDigit -= 9;
                }
                sum += curDigit;
                alt = !alt;
            }
            if ((sum % 10) == 0)
            {
                return "0";
            }
            return (10 - (sum % 10)).ToString();
        }
        #endregion

        #region *** Metodo que valida si el digito verificador de Luhn es correcto
        public static bool ValidaDigitoLuhn(string numero)
        {
            var total = 0;
            var alt = false;
            var digits = numero.ToCharArray();
            for (int i = digits.Length - 1; i >= 0; i--)
            {
                var curDigit = (int)char.GetNumericValue(digits[i]);
                if (alt)
                {
                    curDigit *= 2;
                    if (curDigit > 9)
                        curDigit -= 9;
                }
                total += curDigit;
                alt = !alt;
            }
            return total % 10 == 0;
        }

        #endregion

        #region # **** Metodo para actualizar preferencias del Socio  ****

        public static void ActualizaPreferencias(Guid SocioGuid)
        {
            /*Variables Locales*/
            List<DatosPreferencias> DatosMov = new List<DatosPreferencias>();
            int Asiento_Acum = 0;
            int Asiento_Red = 0;

            DateTime FechaHora_Acum = DateTime.MinValue;
            DateTime FechaHora_Red = DateTime.MinValue;

            string DiaSem_Acum = string.Empty;
            string DiaSem_Red = string.Empty;

            string HoraViaje_Acum = "";
            string HoraViaje_Red = "";

            int MesViaje_Acum = 0;
            int MesViaje_Red = 0;

            int AnioViaje_Acum = 00;
            int AnioViaje_Red = 00;

            Guid OrDestId_acum = Guid.Empty;
            Guid OrDestId_red = Guid.Empty;

            string OrigenDest_Acum = string.Empty;
            string OrigenDest_Reden = string.Empty;

            Guid JustMovId = Guid.Empty;     
            
            /*Recupera todas las acumulaciones y Redenciones relacionadas: Número de asiento, Origenes-Destino, Fecha y Hora de Servicio */
            // Ambos tienen los mismo nombres lógicos a recuperar, a pesar de que sean dos tablas diferentes
            string[] ColumnasAcum_Red = new string[] { "gfa_asiento", "gfa_origendestinoid", "gfa_fechaservicio", "gfa_horaservicio" };

            /*Recuperamos aquellas acumulaciones activas y relacionadas al Socio (Tabla Contact)*/
            EntityCollection Res_Acum = RecuperacionMultiple("gfa_acumulacionkm", ColumnasAcum_Red, "gfa_socioid", SocioGuid.ToString(), "statecode", "Active");

            /*Si existen coincidencias*/
            if (Res_Acum.Entities.Count > 0)
            {
                foreach (Entity Acumuls in Res_Acum.Entities)
                {
                    if (ExisteAtributo("gfa_asiento", Acumuls))
                        Asiento_Acum = (int)Acumuls.Attributes["gfa_asiento"];

                    if (ExisteAtributo("gfa_origendestinoid", Acumuls))
                    {
                        OrDestId_acum = ((EntityReference)Acumuls.Attributes["gfa_origendestinoid"]).Id;
                        //OrDes = Servicio.Retrieve("gfa_catalogoorigendestino", OrDestId_acum, new ColumnSet("gfa_claveorigendestino"));
                        OrigenDest_Acum = OrDestId_acum.ToString();//(MetodosFes.ExisteAtributo("gfa_claveorigendestino", OrDes)) ? (string)OrDes.Attributes["gfa_claveorigendestino"] : string.Empty;
                    }

                    if (ExisteAtributo("gfa_fechaservicio", Acumuls))
                    {
                        FechaHora_Acum = ((DateTime)Acumuls.Attributes["gfa_fechaservicio"]).ToLocalTime();
                        DiaSem_Acum = FechaHora_Acum.ToString("dddd", new CultureInfo("es-MX"));
                        MesViaje_Acum = FechaHora_Acum.Month;
                        AnioViaje_Acum = FechaHora_Acum.Year;

                    }

                    if (ExisteAtributo("gfa_horaservicio", Acumuls))
                    {
                        HoraViaje_Acum = LimpiaCerosEnHoras((string)Acumuls.Attributes["gfa_horaservicio"]);
                    }

                    /* Integramos resultados en una sóla coleccion */
                    DatosMov.Add(new DatosPreferencias
                    {
                        asiento = Asiento_Acum,
                        origendestino = OrigenDest_Acum,
                        fechahoraservicio = FechaHora_Acum,
                        diaservicio = DiaSem_Acum,
                        messervicio = MesViaje_Acum,
                        anioservicio = AnioViaje_Acum,
                        horaservicio = HoraViaje_Acum
                    });
                }

            }

            /*JER 15 Abril: Recuperamos Guid de la Justificación de movimiento  Redención por Expiracion de KM CRE, NO se considera en las preferencias*/
            JustMovId = RecuperaGuidJustMov("CRE");
            // Si existe dicha justificación, netonces recuperamos las redenciones diferentes a CRE y relacionadas al Socio
            if (JustMovId != Guid.Empty)
            {
                /*Recuperamos aquellas Redenciones activas y relacionadas al Socio (Tabla Contact)*/
                EntityCollection Res_Red = RecuperacionMultipleNot("gfa_redencionkm", ColumnasAcum_Red, "gfa_socioid", SocioGuid.ToString(), "statecode", "Active", "gfa_justificaciondemovimientoid", JustMovId.ToString());

                /*Si existen coincidencias*/
                if (Res_Red.Entities.Count > 0)
                {
                    foreach (Entity Redens in Res_Red.Entities)
                    {
                        if (ExisteAtributo("gfa_asiento", Redens))
                            Asiento_Red = (int)Redens.Attributes["gfa_asiento"];

                        if (ExisteAtributo("gfa_origendestinoid", Redens))
                        {
                            OrDestId_red = ((EntityReference)Redens.Attributes["gfa_origendestinoid"]).Id;
                            //OrDes = Servicio.Retrieve("gfa_catalogoorigendestino", OrDestId_red, new ColumnSet("gfa_claveorigendestino"));
                            OrigenDest_Reden = OrDestId_red.ToString();//(MetodosFes.ExisteAtributo("gfa_claveorigendestino", OrDes)) ? (string)OrDes.Attributes["gfa_claveorigendestino"] : string.Empty;
                        }

                        if (ExisteAtributo("gfa_fechaservicio", Redens))
                        {
                            FechaHora_Red = ((DateTime)Redens.Attributes["gfa_fechaservicio"]).ToLocalTime();
                            DiaSem_Red = FechaHora_Red.ToString("dddd", new CultureInfo("es-MX"));
                            MesViaje_Red = FechaHora_Acum.Month;
                            AnioViaje_Red = FechaHora_Red.Year;
                        }

                        if (ExisteAtributo("gfa_horaservicio", Redens))
                        {
                            HoraViaje_Red = LimpiaCerosEnHoras((string)Redens.Attributes["gfa_horaservicio"]);
                        }

                        /* Integramos resultados en una sóla coleccion */
                        DatosMov.Add(new DatosPreferencias
                        {
                            asiento = Asiento_Acum,
                            origendestino = OrigenDest_Reden,
                            fechahoraservicio = FechaHora_Red,
                            diaservicio = DiaSem_Red,
                            messervicio = MesViaje_Red,
                            anioservicio = AnioViaje_Red,
                            horaservicio = HoraViaje_Red
                        });
                    }
                }
            }

             // Si hay datos en la lista de movimientos para preferencias
            if (DatosMov.Count() > 0)
            {
                /*Calcula Asiento Preferido */
                var AsientoPref = from datos_soc in DatosMov
                                  group datos_soc by datos_soc.asiento into NumAsientos
                                  orderby NumAsientos.Count() descending
                                  select new { Asiento = NumAsientos.Key, Conteo = NumAsientos.Count() };

                var Asiento_Fav = AsientoPref.Select(a => a.Asiento).First();

                /*Calcula Origen - Destino Preferido */
                var OrigenDestPref = from datos_soc in DatosMov
                                     group datos_soc by datos_soc.origendestino into OrgDest
                                     orderby OrgDest.Count() descending
                                     select new { OrigenDestino = OrgDest.Key, Conteo = OrgDest.Count() };

                var OrigenDestino_Fav = OrigenDestPref.Select(o => o.OrigenDestino).First();

                /*Calcula Día preferido de viaje */
                var DiaPref = from datos_soc in DatosMov
                              group datos_soc by datos_soc.diaservicio into DiaServ
                              orderby DiaServ.Count() descending
                              select new { DiaViaje = DiaServ.Key, Conteo = DiaServ.Count() };

                var Dia_Fav = DiaPref.Select(d => d.DiaViaje).First();

                /*Calcula Horario Preferido de Viaje */
                var HoraPref = from datos_soc in DatosMov
                               group datos_soc by datos_soc.horaservicio into HoraServ
                               orderby HoraServ.Count() descending
                               select new { HoraViaje = HoraServ.Key, Conteo = HoraServ.Count() };

                var Hora_Fav = HoraPref.Select(h => h.HoraViaje).First();

                /*Calcula número de viajes en el mes y año actual*/
                var NumViajesMes = (from datos_soc in DatosMov
                                    where datos_soc.messervicio == DateTime.Now.ToLocalTime().Month && datos_soc.anioservicio == DateTime.Now.ToLocalTime().Year
                                    select datos_soc.messervicio).Count();

                /*Calcula ultimo viaje realizado, así como la fecha  */
                var OrgDestFecha = from datos_soc in DatosMov
                                   orderby datos_soc.fechahoraservicio descending, datos_soc.horaservicio descending
                                   select new { Fecha = datos_soc.fechahoraservicio, OrgDest = datos_soc.origendestino };

                var UltViaje = OrgDestFecha.Select(or => or.OrgDest).First();

                var FechaUltViaje = OrgDestFecha.Select(f => f.Fecha).First();


                /* PROCESO DE ACTUALIZACION EN CRM */

                Entity Socio_Actualiza = new Entity("contact");
                Socio_Actualiza.Attributes["contactid"] = SocioGuid;

                /*Validamos que exista el Guid del Catalogo */
                //if (RecuperaGuidOrgDest(UltViaje) != Guid.Empty)
                if (UltViaje != string.Empty)
                    Socio_Actualiza.Attributes["gfa_ultimoorigendestinoid"] = new EntityReference("gfa_catalogoorigendestino", new Guid(UltViaje));//RecuperaGuidOrgDest(UltViaje));

                if (Convert.ToDateTime(FechaUltViaje) > DateTime.MinValue)
                    Socio_Actualiza.Attributes["gfa_fechaultimoviaje"] = Convert.ToDateTime(FechaUltViaje);

                Socio_Actualiza.Attributes["gfa_asientopreferido"] = Asiento_Fav;

                /*Validamos que exista el Guid del Catalogo */
                //if (RecuperaGuidOrgDest(OrigenDestino_Fav) != Guid.Empty)
                if (OrigenDestino_Fav != string.Empty)
                    Socio_Actualiza.Attributes["gfa_origendestinopreferidoid"] = new EntityReference("gfa_catalogoorigendestino", new Guid(OrigenDestino_Fav));//RecuperaGuidOrgDest(OrigenDestino_Fav));

                /*Validamos que sea un valor válido el Catálogo de Horario */
                if (CatalogoHorario(Hora_Fav) != -1)
                    Socio_Actualiza.Attributes["preferredappointmenttimecode"] = new OptionSetValue(CatalogoHorario(Hora_Fav));

                /*Validamos que sea un valor válido el Catálogo de Días */
                if (CatalogoDias(Dia_Fav) != -1)
                    Socio_Actualiza.Attributes["preferredappointmentdaycode"] = new OptionSetValue(CatalogoDias(Dia_Fav));

                Socio_Actualiza.Attributes["gfa_frecuenciamensualdeviajes"] = NumViajesMes;

                Servicio.Update(Socio_Actualiza);
            }

        }

        #endregion

        #region Actualiza Preferencias Socio Coporativo
        public static void ActualizaPreferenciasCorp(Guid IdEmpresa)
        {
            string tiposocioid = string.Empty;
            List<DatosPreferenciasMiembros> DatosMov = new List<DatosPreferenciasMiembros>();

            string[] Columnset = new string[] { "gfa_tiposociosid", "gfa_id" };
            EntityCollection Tipocontacto = RecuperacionMultiple("gfa_tiposocios", Columnset, "gfa_id", "MC");

            foreach (Entity MC in Tipocontacto.Entities)
            {
                tiposocioid = MC["gfa_tiposociosid"].ToString();
            }

            #region Revisa miembros
            string[] ColumSet = new string[] { "contactid", "parentcustomerid", "gfa_ultimoorigendestinoid", "gfa_fechaultimoviaje", "gfa_asientopreferido", 
                                                "gfa_origendestinopreferidoid", "preferredappointmenttimecode", "preferredappointmenttimecode", 
                                                "preferredappointmentdaycode","gfa_frecuenciamensualdeviajes"};




            string UltViaje;// gfa_ultimoorigendestinoid  new EntityReference("gfa_catalogoorigendestino", RecuperaGuidOrgDest(UltViaje));
            string OrigenDestino_Fav;// ["gfa_origendestinopreferidoid"] = new EntityReference("gfa_catalogoorigendestino", RecuperaGuidOrgDest(OrigenDestino_Fav));


            DateTime FechaUltViaje;//gfa_fechaultimoviaje
            int Asiento_Fav;//gfa_asientopreferido
            int Hora_Fav; //preferredappointmenttimecode
            int Dia_Fav; //"preferredappointmentdaycode"] = new OptionSetValue(CatalogoDias(Dia_Fav));
            int NumViajesMes;//gfa_frecuenciamensualdeviajes         

            EntityCollection Contactos = RecuperacionMultiple("contact", ColumSet, "parentcustomerid", IdEmpresa.ToString(), "gfa_tipodesocioid", tiposocioid);

            /*************************************************************/

            if (Contactos.Entities.Count == 0)
                return;

            foreach (Entity contact in Contactos.Entities)
            {

                #region Recupera preferencias miembros.

                UltViaje = ExisteAtributo("gfa_ultimoorigendestinoid", contact) ? ((EntityReference)contact["gfa_ultimoorigendestinoid"]).Id.ToString() : "";
                OrigenDestino_Fav = ExisteAtributo("gfa_origendestinopreferidoid", contact) ? ((EntityReference)contact["gfa_origendestinopreferidoid"]).Id.ToString() : "";
                FechaUltViaje = ExisteAtributo("gfa_fechaultimoviaje", contact) ? (DateTime)contact["gfa_fechaultimoviaje"] : DateTime.MinValue;
                Asiento_Fav = ExisteAtributo("gfa_asientopreferido", contact) ? (int)contact["gfa_asientopreferido"] : 0;
                Hora_Fav = ExisteAtributo("preferredappointmenttimecode", contact) ? ((OptionSetValue)contact["preferredappointmenttimecode"]).Value : 0;
                Dia_Fav = ExisteAtributo("preferredappointmentdaycode", contact) ? ((OptionSetValue)contact["preferredappointmentdaycode"]).Value : 0;
                NumViajesMes = ExisteAtributo("gfa_frecuenciamensualdeviajes", contact) ? (int)(contact["gfa_frecuenciamensualdeviajes"]) : 0;

                /* Integramos resultados en una sóla coleccion */
                DatosMov.Add(new DatosPreferenciasMiembros
                {
                    pref_asiento = Asiento_Fav,
                    pref_dia = Dia_Fav,
                    pref_hora = Hora_Fav,
                    ult_origendestino = UltViaje,
                    pref_origendestino = OrigenDestino_Fav,
                    numviajes = NumViajesMes,
                    Ultimoviaje = FechaUltViaje
                });

                #endregion
            }

            /*Asiento Preferido */
            var AsientoPref = from datos_soc in DatosMov
                              group datos_soc by datos_soc.pref_asiento into NumAsientos
                              orderby NumAsientos.Count() descending
                              select new { Asiento = NumAsientos.Key, Conteo = NumAsientos.Count() };

            var Asiento_res = AsientoPref.Select(a => a.Asiento).First();

            /*dia Preferido */
            var DiaPref = from datos_soc in DatosMov
                          group datos_soc by datos_soc.pref_dia into NumDias
                          orderby NumDias.Count() descending
                          select new { Dia = NumDias.Key, Conteo = NumDias.Count() };

            var Dia_res = DiaPref.Select(a => a.Dia).First();

            /*Hora Preferida */
            var HoraPref = from datos_soc in DatosMov
                           group datos_soc by datos_soc.pref_hora into Numhora
                           orderby Numhora.Count() descending
                           select new { Hora = Numhora.Key, Conteo = Numhora.Count() };

            var Hora_res = HoraPref.Select(a => a.Hora).First();

            /*Origen-Destino Preferido */
            var OriDesPref = from datos_soc in DatosMov
                             group datos_soc by datos_soc.pref_origendestino into Numorides
                             orderby Numorides.Count() descending
                             select new { OriDes = Numorides.Key, Conteo = Numorides.Count() };

            var orides_res = OriDesPref.Select(a => a.OriDes).First();


            /*Calcula ultimo viaje realizado, así como la fecha  */
            var UltOrgDestFecha = from datos_soc in DatosMov
                                  orderby datos_soc.Ultimoviaje, datos_soc.pref_hora descending
                                  select new { Fecha = datos_soc.Ultimoviaje, OrgDest = datos_soc.ult_origendestino };

            var FechaUltViaje_res = UltOrgDestFecha.Select(or => or.Fecha).First();

            var UltViaje_res = UltOrgDestFecha.Select(f => f.OrgDest).First();

            /*Calcula Numero de viajes al mes */
            var NumViajesd = from datos_soc in DatosMov
                             select new { viajesxmex = datos_soc.numviajes };
            var Numviajesall = NumViajesd.Select(a => a.viajesxmex).Sum();


            /* PROCESO DE ACTUALIZACION EN CRM */

            Entity Socio_Actualiza = new Entity("account");
            Socio_Actualiza.Attributes["accountid"] = IdEmpresa;

            /*Validamos que exista el Guid del Catalogo */
            if (UltViaje_res != string.Empty)
                Socio_Actualiza.Attributes["gfa_ultimoorigendestinoid"] = new EntityReference("gfa_catalogoorigendestino", new Guid(UltViaje_res));

            Socio_Actualiza.Attributes["gfa_fechaultimoviaje"] = FechaUltViaje_res;
            Socio_Actualiza.Attributes["gfa_asientopreferido"] = Asiento_res;

            /*Validamos que exista el Guid del Catalogo */
            if (orides_res != string.Empty)
                Socio_Actualiza.Attributes["gfa_origendestinopreferidoid"] = new EntityReference("gfa_catalogoorigendestino", new Guid(orides_res));

            /*Validamos que sea un valor válido el Catálogo de Horario */
            if (Hora_res != 0)
                Socio_Actualiza.Attributes["preferredappointmenttimecode"] = new OptionSetValue(Hora_res);

            /*Validamos que sea un valor válido el Catálogo de Días */
            if (Dia_res != -1)
                Socio_Actualiza.Attributes["preferredappointmentdaycode"] = new OptionSetValue(Dia_res);

            Socio_Actualiza.Attributes["gfa_frecuenciamensualdeviajes"] = Numviajesall;

            Servicio.Update(Socio_Actualiza);

            #endregion
        }
        #endregion

        #region # Método para obtener Catálogo de Origenes Destino

        public static Guid RecuperaGuidOrgDest(string valor)
        {
            Guid DevuelveId = Guid.Empty;

            EntityCollection Res_Cat = RecuperacionMultiple("gfa_catalogoorigendestino", new string[] { "gfa_catalogoorigendestinoid" }, "gfa_claveorigendestino", valor, "statecode", "Active");

            if (Res_Cat.Entities.Count > 0)
            {
                foreach (Entity Cat in Res_Cat.Entities)
                {
                    if (ExisteAtributo("gfa_catalogoorigendestinoid", Cat))
                        DevuelveId = (Guid)Cat.Attributes["gfa_catalogoorigendestinoid"];
                }
            }
            return DevuelveId;
        }

        #endregion

        #region # Método para obtener Catálogo Horario Preferido en CRM
        private static int CatalogoHorario(string hrs)
        {
            int DevuelveValor = -1;
            int hora = 0;
            // Validamos que existan datos
            if (hrs != "")
            {
                // Si hay datos, se valida el operador de la Hora
                if (hrs.IndexOf(':') > 0)
                {
                    // Si existe, entonces se dividen los datos por el :
                    string[] HrsDiv = hrs.Split(':');
                    // Si hay dos datos despues del split 23:59
                    if (HrsDiv.Length.Equals(2))
                    {
                        // Si hay datos de Hora
                        if (HrsDiv[0] != "")
                        {
                            // Convertimos el string en un entero
                            hora = Convert.ToInt16(HrsDiv[0]);
                            // Se realizan las validaciones de los horarios
                            if (hora >= 7 && hora < 12)
                            {
                                DevuelveValor = 1;  // Mañana
                            }

                            if (hora >= 12 && hora < 20)
                            {
                                DevuelveValor = 2; // Tarde 
                            }

                            if (hora >= 20 && hora <= 23)
                            {
                                DevuelveValor = 3;  // Noche
                            }

                            if (hora.Equals(0))
                            {
                                DevuelveValor = 4; //(Descartado)100000000; // Madrugada
                            }

                            if (hora >= 0 && hora < 7)
                            {
                                DevuelveValor = 4;//(Descartado)100000000; // Madrugada
                            }
                        }
                    }
                }
            }

            return DevuelveValor;
        }

        #endregion

        #region # Método para limpiar ceros como primer digito
        private static string LimpiaCerosEnHoras(string hrs)
        {
            int Hora_Int = 0;
            string Mins_Str = "";
            // Validamos que existan datos
            if (hrs != "")
            {
                // Si hay datos, se valida el operador de la Hora
                if (hrs.IndexOf(':') > 0)
                {
                    // Si existe, entonces se dividen los datos por el :
                    string[] HrsDiv = hrs.Split(':');
                    // Si hay dos datos en el arreglo, despues del split 23:59
                    if (HrsDiv.Length.Equals(2))
                    {
                        // Si hay datos de Hora, los convertimos a entero para eliminar ceros
                        if (HrsDiv[0] != "")
                            Hora_Int = int.Parse(HrsDiv[0]);
                        // Dejamos los demás intacto como string
                        if (HrsDiv[1] != "")
                            Mins_Str = HrsDiv[1];
                    }
                }
            }

            return Hora_Int.ToString() + ":" + Mins_Str;
        }

        #endregion

        #region # Método para traducir Catálogo de Estado Actual con Estado anterior

        public static int CatalogoEstadoAnterior(int Valor)
        {
            int Devuelve = -1;
            switch (Valor)
            {
                case 1: Devuelve = 223060000;
                    break;

                case 223060003: Devuelve = 223060001;
                    break;

                case 223060002: Devuelve = 223060002;
                    break;

                case 223060005: Devuelve = 223060003;
                    break;

                case 223060006: Devuelve = 223060004;
                    break;

                case 2: Devuelve = 223060005;
                    break;

                case 223060004: Devuelve = 223060006;
                    break;
            }
            return Devuelve;
        }
        #endregion

        #region # Método para obtener Catálogo Días en CRM
        private static int CatalogoDias(string diacad)
        {
            int DevuelveValor = -1;

            switch (diacad)
            {
                case "domingo": DevuelveValor = 0;
                    break;
                case "lunes": DevuelveValor = 1;
                    break;
                case "martes": DevuelveValor = 2;
                    break;
                case "miércoles": DevuelveValor = 3;
                    break;
                case "jueves": DevuelveValor = 4;
                    break;
                case "viernes": DevuelveValor = 5;
                    break;
                case "sábado": DevuelveValor = 6;
                    break;
            }
            return DevuelveValor;
        }

        #endregion

        #region # Método para obtener Catálogo de estados del boleto redimido
        public static int CatalogoEstadoBoleto(string edo)
        {
            int DevuelveValor = -1;
            // sin Usar (VE), Canjeado (CA) , Cancelado (CS),
            switch (edo)
            {
                case "VE": DevuelveValor = 1;
                    break;
                case "CA": DevuelveValor = 2;
                    break;
                case "CS": DevuelveValor = 3;
                    break;
            }
            return DevuelveValor;
        }

        #endregion

        #region # *** Metodo para Afectar Km en base al movimiento
        public enum Movimiento
        {
            Acumulacion,
            KmExtra,
            Redencion,
            CancelacionViaje
        }

        public enum Socios
        {
            Plus,
            Corporativo
        }

        /* JER 15 ABRIL : Método para afectar kilómetros en Redenciones, se verifica la justificación de la Redención*/
        public static bool AfectaKilometros(Socios Soc, Guid SocioId, int KmObtenidos, Movimiento Mov, Guid RedJusMovId, string ClaveMov)
        {
            bool Exito = false;
            int EstadoReg = 0;
            string ClaveJustMov = string.Empty;

            /*Calculo del nuevo kilometraje */
            int KmsAcum = 0;
            int KmsBono = 0;
            int KmsRed = 0;
            int KmsDisp = 0;

            Entity Socio = null;

            /*Recuperamos los datos de Kms del Socio en cuestión */
            if (Soc.Equals(Socios.Plus))
                Socio = Servicio.Retrieve("contact", SocioId, new ColumnSet("gfa_kmacumulados", "gfa_kmbono", "gfa_kmredimidos", "gfa_kmdisponibles", "statecode"));
            else
                Socio = Servicio.Retrieve("account", SocioId, new ColumnSet("gfa_kmacumulados", "gfa_kmbono", "gfa_kmredimidos", "gfa_kmdisponibles", "statecode"));

            // Recuperamos la Justificación del movimiento de la redención
            Entity JustMovRed = Servicio.Retrieve("gfa_justmov", RedJusMovId, new ColumnSet("gfa_id"));
            if (MetodosFes.ExisteAtributo("gfa_id", JustMovRed))
                ClaveJustMov = (string)JustMovRed.Attributes["gfa_id"];

            // Validamos que el Socio esté activo
            if (MetodosFes.ExisteAtributo("statecode", Socio))
            {
                EstadoReg = ((OptionSetValue)Socio.Attributes["statecode"]).Value;

                /*JER 15 Abril: Se agrega condición para que se afecte el KM si el Socio está activo o si la redención es por expiración. (CRE) */
                if ((EstadoReg.Equals(0)) || ClaveJustMov.Equals("CRE"))
                {
                    // Si el Socio está activo se realiza todo el proceso 
                    //if (((OptionSetValue)Socio.Attributes["statecode"]).Value.Equals(0))
                    //{
                    if (ExisteAtributo("gfa_kmacumulados", Socio))
                        KmsAcum = (int)Socio.Attributes["gfa_kmacumulados"];
                    if (ExisteAtributo("gfa_kmbono", Socio))
                        KmsBono = (int)Socio.Attributes["gfa_kmbono"];
                    if (ExisteAtributo("gfa_kmredimidos", Socio))
                        KmsRed = (int)Socio.Attributes["gfa_kmredimidos"];
                    if (ExisteAtributo("gfa_kmdisponibles", Socio))
                        KmsDisp = (int)Socio.Attributes["gfa_kmdisponibles"];

                    /*Realizamos el recalculo de los kilómetros, se agregan los que vienen como extras, afecta a KM Bono */
                    switch (Mov)
                    {
                        case Movimiento.Acumulacion: KmsAcum = KmsAcum + KmObtenidos;
                            break;

                        case Movimiento.KmExtra: KmsBono = KmsBono + KmObtenidos;
                            break;

                        case Movimiento.Redencion: KmsRed = KmsRed + KmObtenidos;
                            break;

                        case Movimiento.CancelacionViaje: KmsRed = KmsRed + KmObtenidos;
                            break;
                    }

                    /*Calculo de Km Disponibles */
                    KmsDisp = KmsAcum + KmsBono - KmsRed;

                    Entity Socio_Act = null;

                    /*Si los KM Disp son mayores a cero */
                    if (KmsDisp >= 0)
                    {
                        /*Actualización del Kilometraje */
                        if (Soc.Equals(Socios.Plus))
                        {
                            Socio_Act = new Entity("contact");
                            Socio_Act.Attributes["contactid"] = SocioId;
                        }
                        else
                        {
                            Socio_Act = new Entity("account");
                            Socio_Act.Attributes["accountid"] = SocioId;
                        }

                        Socio_Act.Attributes["gfa_kmacumulados"] = KmsAcum;
                        Socio_Act.Attributes["gfa_kmbono"] = KmsBono;
                        Socio_Act.Attributes["gfa_kmredimidos"] = KmsRed;
                        Socio_Act.Attributes["gfa_kmdisponibles"] = KmsDisp;

                        if (RecuperaGuidMovimiento(ClaveMov) != Guid.Empty)
                            Socio_Act.Attributes["gfa_ultimomovimientoid"] = new EntityReference("gfa_catalogomovimientos", RecuperaGuidMovimiento(ClaveMov));

                        /*Actualizamos la fecha del ultimo movimiento*/
                        Socio_Act.Attributes["gfa_fechaultimomovimiento"] = DateTime.Now.ToLocalTime();
                        /*Ejecutamos la Actualización */
                        Servicio.Update(Socio_Act);
                        /*Todo se realizó correctamente*/
                        Exito = true;
                    }
                    //}
                }
            }
            return Exito;
        }

        /*Método para colocar kilómetros acumulados por acreditaciones de integración*/
        public static bool AfectaKilometros(Socios Soc, Guid SocioId, int KmObtenidos, Movimiento Mov, string ClaveMov)
        {
            bool Exito = false;

            /*Calculo del nuevo kilometraje */
            int KmsAcum = 0;
            int KmsBono = 0;
            int KmsRed = 0;
            int KmsDisp = 0;

            Entity Socio = null;

            /*Recuperamos los datos de Kms del Socio en cuestión */
            if (Soc.Equals(Socios.Plus))
                Socio = Servicio.Retrieve("contact", SocioId, new ColumnSet("gfa_kmacumulados", "gfa_kmbono", "gfa_kmredimidos", "gfa_kmdisponibles", "statecode"));
            else
                Socio = Servicio.Retrieve("account", SocioId, new ColumnSet("gfa_kmacumulados", "gfa_kmbono", "gfa_kmredimidos", "gfa_kmdisponibles", "statecode"));

            // Validamos que el Socio esté activo
            if (MetodosFes.ExisteAtributo("statecode", Socio))
            {
                // Si el Socio está activo se realiza todo el proceso 
                if (((OptionSetValue)Socio.Attributes["statecode"]).Value.Equals(0))
                {
                    if (ExisteAtributo("gfa_kmacumulados", Socio))
                        KmsAcum = (int)Socio.Attributes["gfa_kmacumulados"];
                    if (ExisteAtributo("gfa_kmbono", Socio))
                        KmsBono = (int)Socio.Attributes["gfa_kmbono"];
                    if (ExisteAtributo("gfa_kmredimidos", Socio))
                        KmsRed = (int)Socio.Attributes["gfa_kmredimidos"];
                    if (ExisteAtributo("gfa_kmdisponibles", Socio))
                        KmsDisp = (int)Socio.Attributes["gfa_kmdisponibles"];

                    /*Realizamos el recalculo de los kilómetros, se agregan los que vienen como extras, afecta a KM Bono */
                    switch (Mov)
                    {
                        case Movimiento.Acumulacion: KmsAcum = KmsAcum + KmObtenidos;
                            break;

                        case Movimiento.KmExtra: KmsBono = KmsBono + KmObtenidos;
                            break;

                        case Movimiento.Redencion: KmsRed = KmsRed + KmObtenidos;
                            break;

                        case Movimiento.CancelacionViaje: KmsRed = KmsRed + KmObtenidos;
                            break;
                    }

                    /*Calculo de Km Disponibles */
                    KmsDisp = KmsAcum + KmsBono - KmsRed;

                    Entity Socio_Act = null;

                    /*Si los KM Disp son mayores a cero */
                    if (KmsDisp >= 0)
                    {
                        /*Actualización del Kilometraje */
                        if (Soc.Equals(Socios.Plus))
                        {
                            Socio_Act = new Entity("contact");
                            Socio_Act.Attributes["contactid"] = SocioId;
                        }
                        else
                        {
                            Socio_Act = new Entity("account");
                            Socio_Act.Attributes["accountid"] = SocioId;
                        }

                        Socio_Act.Attributes["gfa_kmacumulados"] = KmsAcum;
                        Socio_Act.Attributes["gfa_kmbono"] = KmsBono;
                        Socio_Act.Attributes["gfa_kmredimidos"] = KmsRed;
                        Socio_Act.Attributes["gfa_kmdisponibles"] = KmsDisp;

                        if (RecuperaGuidMovimiento(ClaveMov) != Guid.Empty)
                            Socio_Act.Attributes["gfa_ultimomovimientoid"] = new EntityReference("gfa_catalogomovimientos", RecuperaGuidMovimiento(ClaveMov));

                        /*Actualizamos la fecha del ultimo movimiento*/
                        Socio_Act.Attributes["gfa_fechaultimomovimiento"] = DateTime.Now.ToLocalTime();
                        /*Ejecutamos la Actualización */
                        Servicio.Update(Socio_Act);
                        /*Todo se realizó correctamente*/
                        Exito = true;
                    }
                }
            }
            return Exito;
        }

        /*Sobrecargado para colocar kilómetros bono en caso de no completar los minimos requeridos*/
        public static bool AfectaKilometros(Socios Soc, Guid SocioId, int Bono, int KmObtenidos, Movimiento Mov, string ClaveMov)
        {
            bool Exito = false;

            /*Calculo del nuevo kilometraje */
            int KmsAcum = 0;
            int KmsBono = 0;
            int KmsRed = 0;
            int KmsDisp = 0;

            Entity Socio = null;

            /*Recuperamos los datos de Kms del Socio en cuestión */
            if (Soc.Equals(Socios.Plus))
                Socio = Servicio.Retrieve("contact", SocioId, new ColumnSet("gfa_kmacumulados", "gfa_kmbono", "gfa_kmredimidos", "gfa_kmdisponibles", "statecode"));
            else
                Socio = Servicio.Retrieve("account", SocioId, new ColumnSet("gfa_kmacumulados", "gfa_kmbono", "gfa_kmredimidos", "gfa_kmdisponibles", "statecode"));

            // Validamos que el Socio esté activo
            if (MetodosFes.ExisteAtributo("statecode", Socio))
            {
                // Si el Socio está activo se realiza todo el proceso 
                if (((OptionSetValue)Socio.Attributes["statecode"]).Value.Equals(0))
                {
                    if (ExisteAtributo("gfa_kmacumulados", Socio))
                        KmsAcum = (int)Socio.Attributes["gfa_kmacumulados"];
                    if (ExisteAtributo("gfa_kmbono", Socio))
                        KmsBono = (int)Socio.Attributes["gfa_kmbono"];
                    if (ExisteAtributo("gfa_kmredimidos", Socio))
                        KmsRed = (int)Socio.Attributes["gfa_kmredimidos"];
                    if (ExisteAtributo("gfa_kmdisponibles", Socio))
                        KmsDisp = (int)Socio.Attributes["gfa_kmdisponibles"];

                    /*Realizamos el recalculo de los kilómetros, se agregan los que vienen como extras, afecta a KM Bono */
                    switch (Mov)
                    {
                        case Movimiento.Acumulacion: if (Bono != 0)
                            {
                                KmsBono = KmsBono + Bono;
                                KmsAcum = KmsAcum + (KmObtenidos - Bono);
                            }
                            else
                                KmsAcum = KmsAcum + KmObtenidos;
                            break;

                        case Movimiento.KmExtra: KmsBono = KmsBono + KmObtenidos;
                            break;

                        case Movimiento.Redencion: KmsRed = KmsRed + KmObtenidos;
                            break;
                    }

                    /*Calculo de Km Disponibles */
                    KmsDisp = KmsAcum + KmsBono - KmsRed;

                    Entity Socio_Act = null;

                    /*Si los KM Disp son mayores a cero */
                    if (KmsDisp >= 0)
                    {
                        /*Actualización del Kilometraje */
                        if (Soc.Equals(Socios.Plus))
                        {
                            Socio_Act = new Entity("contact");
                            Socio_Act.Attributes["contactid"] = SocioId;
                        }
                        else
                        {
                            Socio_Act = new Entity("account");
                            Socio_Act.Attributes["accountid"] = SocioId;
                        }

                        Socio_Act.Attributes["gfa_kmacumulados"] = KmsAcum;
                        Socio_Act.Attributes["gfa_kmbono"] = KmsBono;
                        Socio_Act.Attributes["gfa_kmredimidos"] = KmsRed;
                        Socio_Act.Attributes["gfa_kmdisponibles"] = KmsDisp;

                        if (RecuperaGuidMovimiento(ClaveMov) != Guid.Empty)
                            Socio_Act.Attributes["gfa_ultimomovimientoid"] = new EntityReference("gfa_catalogomovimientos", RecuperaGuidMovimiento(ClaveMov));

                        /*Actualizamos la fecha del ultimo movimiento*/
                        Socio_Act.Attributes["gfa_fechaultimomovimiento"] = DateTime.Now.ToLocalTime();
                        /*Ejecutamos la Actualización */
                        Servicio.Update(Socio_Act);
                        /*Todo se realizó correctamente*/
                        Exito = true;
                    }
                }
            }
            return Exito;
        }

        /*Sobrecargado de Afecta Kilómetros, en el caso de Km Extra con Just de Mov: Compra, Puntos por Promocion*/
        public static bool AfectaKilometros(Socios Soc, Guid SocioId, int KmObtenidos, Movimiento Mov, string ClaveMov, Guid JustMovId)
        {
            /*Bandera para conocer Si se realizó o no el cambio*/
            bool Exito = false;
            /*Claves permitidas en Km Extra */
            /* KM Extra, KM por Compra, KM por Promo */
            /*Aquellos JustMov consideradas como Km Extra*/
            List<string> JustMovPerm = new List<string>(new string[] { "AA6", "CKM", "KMP" }); // 
            string ClaveJustMov = string.Empty;

            /*Calculo del nuevo kilometraje */
            int KmsAcum = 0;
            int KmsBono = 0;
            int KmsRed = 0;
            int KmsDisp = 0;

            Entity Socio = null;

            /*Recuperamos los datos de Kms del Socio en cuestión */
            if (Soc.Equals(Socios.Plus))
                Socio = Servicio.Retrieve("contact", SocioId, new ColumnSet("gfa_kmacumulados", "gfa_kmbono", "gfa_kmredimidos", "gfa_kmdisponibles", "statecode"));
            else
                Socio = Servicio.Retrieve("account", SocioId, new ColumnSet("gfa_kmacumulados", "gfa_kmbono", "gfa_kmredimidos", "gfa_kmdisponibles", "statecode"));

            // Validamos que el Socio esté activo
            if (MetodosFes.ExisteAtributo("statecode", Socio))
            {
                // Si el Socio está activo se realiza todo el proceso 
                if (((OptionSetValue)Socio.Attributes["statecode"]).Value.Equals(0))
                {
                    if (ExisteAtributo("gfa_kmacumulados", Socio))
                        KmsAcum = (int)Socio.Attributes["gfa_kmacumulados"];
                    if (ExisteAtributo("gfa_kmbono", Socio))
                        KmsBono = (int)Socio.Attributes["gfa_kmbono"];
                    if (ExisteAtributo("gfa_kmredimidos", Socio))
                        KmsRed = (int)Socio.Attributes["gfa_kmredimidos"];
                    if (ExisteAtributo("gfa_kmdisponibles", Socio))
                        KmsDisp = (int)Socio.Attributes["gfa_kmdisponibles"];

                    /*Realizamos el recalculo de los kilómetros, se agregan los que vienen como extras, afecta a KM Bono */
                    switch (Mov)
                    {
                        case Movimiento.Acumulacion: KmsAcum = KmsAcum + KmObtenidos;
                            break;

                        case Movimiento.KmExtra: KmsBono = KmsBono + KmObtenidos;
                            break;

                        case Movimiento.Redencion: KmsRed = KmsRed + KmObtenidos;
                            break;
                    }

                    /*Calculo de Km Disponibles */
                    KmsDisp = KmsAcum + KmsBono - KmsRed;

                    Entity Socio_Act = null;

                    /*Si los KM Disp son mayores a cero */
                    if (KmsDisp >= 0)
                    {

                        /*Actualización del Kilometraje */
                        if (Soc.Equals(Socios.Plus))
                        {
                            Socio_Act = new Entity("contact");
                            Socio_Act.Attributes["contactid"] = SocioId;
                        }
                        else
                        {
                            Socio_Act = new Entity("account");
                            Socio_Act.Attributes["accountid"] = SocioId;
                        }

                        Socio_Act.Attributes["gfa_kmacumulados"] = KmsAcum;
                        Socio_Act.Attributes["gfa_kmbono"] = KmsBono;
                        Socio_Act.Attributes["gfa_kmredimidos"] = KmsRed;
                        Socio_Act.Attributes["gfa_kmdisponibles"] = KmsDisp;

                        /*Si el ID de la Justificación de Mov es diferente de Nulo*/
                        if (JustMovId != Guid.Empty)
                        {
                            /*Realizamos petición a la Just de Mov */
                            Entity CatJustMov = Servicio.Retrieve("gfa_justmov", JustMovId, new ColumnSet("gfa_id"));

                            if (ExisteAtributo("gfa_id", CatJustMov))
                            {
                                /*Asignamos Clave de la Just de Mov de los Kms Extra */
                                ClaveJustMov = (string)CatJustMov.Attributes["gfa_id"];
                                /*Si la clave es igual a las permitidas, entonces se realiza el seteo del ultimo movimiento relacionado a Kilometros Extra */
                                if (JustMovPerm.Contains(ClaveJustMov))
                                {
                                    if (RecuperaGuidMovimiento(ClaveMov) != Guid.Empty)
                                        Socio_Act.Attributes["gfa_ultimomovimientoid"] = new EntityReference("gfa_catalogomovimientos", RecuperaGuidMovimiento(ClaveMov));
                                }

                                /*Si la Justificación de Movimiento es Cancelación por Redenciones */
                                if (ClaveJustMov.Equals("RCT"))
                                {
                                    /*Recuperamos el Guid del movimiento relacionado a Cancelación de Redenciones */
                                    if (RecuperaGuidMovimiento("CR") != Guid.Empty)
                                        Socio_Act.Attributes["gfa_ultimomovimientoid"] = new EntityReference("gfa_catalogomovimientos", RecuperaGuidMovimiento("CR"));
                                }
                            }
                        }

                        /*Actualizamos la fecha del ultimo movimiento*/
                        Socio_Act.Attributes["gfa_fechaultimomovimiento"] = DateTime.Now.ToLocalTime();
                        /*Ejecutamos la Actualización */
                        Servicio.Update(Socio_Act);
                        /*Todo se realizó correctamente*/
                        Exito = true;
                    }
                }
            }
            return Exito;
        }

        #endregion

        #region # *** Método para Encontrar Guid de Catalogo de Medios, en base a la clave Proporcionada
        public static Guid RecuperaGuidMedio(string ClaveMedio)
        {
            Guid MedioId = Guid.Empty;

            /*Buscamos ID del Tipo de Movimiento, para Actualizar el Ultimo Movimiento realizado*/
            EntityCollection ResMedios = RecuperacionMultiple("gfa_catalogodemedios", new string[] { "gfa_catalogodemediosid" }, "statecode", "Active", "gfa_id", ClaveMedio);
            /*Recorremos Resultados */
            if (ResMedios.Entities.Count > 0)
            {
                foreach (Entity CatMedio in ResMedios.Entities)
                {
                    if (ExisteAtributo("gfa_catalogodemediosid", CatMedio))
                        MedioId = (Guid)CatMedio.Attributes["gfa_catalogodemediosid"];
                }
            }
            return MedioId;
        }
        #endregion

        #region # *** Método para Encontrar Guid de Catalogo de Movimientos, en base a la clave Proporcionada
        public static Guid RecuperaGuidMovimiento(string ClaveMov)
        {
            Guid MovId = Guid.Empty;

            /*Buscamos ID del Tipo de Movimiento, para Actualizar el Ultimo Movimiento realizado*/
            EntityCollection ResMovs = RecuperacionMultiple("gfa_catalogomovimientos", new string[] { "gfa_catalogomovimientosid" }, "statecode", "Active", "gfa_idmovimiento", ClaveMov);
            /*Recorremos Resultados */
            if (ResMovs.Entities.Count > 0)
            {
                foreach (Entity CatMov in ResMovs.Entities)
                {
                    if (ExisteAtributo("gfa_catalogomovimientosid", CatMov))
                        MovId = (Guid)CatMov.Attributes["gfa_catalogomovimientosid"];
                }
            }
            return MovId;
        }
        #endregion

        #region # *** Método para Encontrar Guid de Catalogo de Movimientos, en base a la clave Proporcionada
        public static Guid RecuperaGuidTipoSocio(string ClaveTipo)
        {
            Guid TipoId = Guid.Empty;

            /*Buscamos ID del Tipo de Socio */
            EntityCollection ResTipos = RecuperacionMultiple("gfa_tiposocios", new string[] { "gfa_tiposociosid" }, "statecode", "Active", "gfa_id", ClaveTipo);
            /*Recorremos Resultados */
            if (ResTipos.Entities.Count > 0)
            {
                foreach (Entity TipoSoc in ResTipos.Entities)
                {
                    if (ExisteAtributo("gfa_tiposociosid", TipoSoc))
                        TipoId = (Guid)TipoSoc.Attributes["gfa_tiposociosid"];
                }
            }
            return TipoId;
        }
        #endregion

        #region # *** Método para Encontrar Guid de Catalogo Justificaicón de Movimientos, en base a la clave Proporcionada
        public static Guid RecuperaGuidJustMov(string ClaveJustMov)
        {
            Guid JustMovId = Guid.Empty;

            /*Buscamos ID de la Justificación de Movimiento*/
            EntityCollection ResJustMov = RecuperacionMultiple("gfa_justmov", new string[] { "gfa_justmovid" }, "statecode", "Active", "gfa_id", ClaveJustMov);
            /*Recorremos Resultados */
            if (ResJustMov.Entities.Count > 0)
            {
                foreach (Entity CatJusMov in ResJustMov.Entities)
                {
                    if (ExisteAtributo("gfa_justmovid", CatJusMov))
                        JustMovId = (Guid)CatJusMov.Attributes["gfa_justmovid"];
                }
            }
            return JustMovId;
        }
        #endregion
      

        #region # *** Método para encontrar Guid de Categoría
        public static Guid RecuperaGuidOficina(string ClaveOf)
        {
            Guid OfId = Guid.Empty;

            /* Recuperamos todas las Oficinas coincidentes con la enviada por GFA  */
            EntityCollection Oficinas = MetodosFes.RecuperacionMultiple("gfa_catalogo_ofdest_sp", new string[] { "gfa_catalogo_ofdest_spid" }, "gfa_claveofdest", ClaveOf);

            if (Oficinas.Entities.Count > 0)
            {
                foreach (Entity Ofic in Oficinas.Entities)
                {
                    if (MetodosFes.ExisteAtributo("gfa_catalogo_ofdest_spid", Ofic))
                    {
                        OfId = (Guid)Ofic.Attributes["gfa_catalogo_ofdest_spid"];
                    }
                }
            }
            return OfId;
        }

        #endregion

        #region # **** Método para calcular Importe Total de Acumulaciones y Redenciones ** DESCONTINUADO (PRIMERA VERSION)
        public static void CalculaTotalImportes(Guid SocioId, Movimiento Mov)
        {
            //decimal TotalAcum = 0;
            //decimal TotalRed = 0;

            //EntityCollection Resultados = null;
            //EntityCollection ResultadosRed = null;

            ///*Recuperamos todas las Acumulaciones o Redenciones Activas diferentes a la Actual */
            //if (Mov.Equals(Movimiento.Acumulacion))
            //    Resultados = RecuperacionMultiple("gfa_acumulacionkm", new string[] { "gfa_importeservicio" }, "statecode", "Active", "gfa_socioid", SocioId.ToString());

            //if (Mov.Equals(Movimiento.Redencion))
            //    ResultadosRed = RecuperacionMultiple("gfa_redencionkm", new string[] { "gfa_importeservicio" }, "statecode", "Active", "gfa_socioid", SocioId.ToString());

            ///* Sumamos todos los importes   */
            //if (Resultados != null)
            //{
            //    if (Resultados.Entities.Count > 0)
            //    {
            //        foreach (Entity Res in Resultados.Entities)
            //        {
            //            if (ExisteAtributo("gfa_importeservicio", Res))
            //                TotalAcum += ((Money)Res.Attributes["gfa_importeservicio"]).Value;
            //        }
            //    }
            //}

            ///*Separamos Redenciones debido a que los nombre lógicos son Iguales*/
            //if (ResultadosRed != null)
            //{
            //    if (ResultadosRed.Entities.Count > 0)
            //    {
            //        foreach (Entity ResRed in ResultadosRed.Entities)
            //        {
            //            if (ExisteAtributo("gfa_importeservicio", ResRed))
            //                TotalRed += ((Money)ResRed.Attributes["gfa_importeservicio"]).Value;
            //        }
            //    }
            //}

            ///* Actualizamos los importes en el Socio*/
            //Entity Socio_Act = new Entity("contact");
            //Socio_Act.Attributes["contactid"] = SocioId;
            ///*Se valida si existen totales para ser actualizados */
            //if (TotalRed != 0)
            //    Socio_Act.Attributes["gfa_importetotalredenciones"] = new Money(TotalRed);
            //if (TotalAcum != 0)
            //    Socio_Act.Attributes["gfa_importetotalacumulaciones"] = new Money(TotalAcum);

            //Servicio.Update(Socio_Act);
        }
        #endregion

        #region # **** Método para calcular Importe Total de Acumulaciones y Redenciones Version 11 Abril 2014
        public static void CalculaTotalImportes(Socios Tipo, Guid SocioId, Movimiento Mov, Guid IdMov)
        {
            decimal ImporteServ = 0;
            decimal TotalAcum = 0;
            decimal TotalRed = 0;

            Entity Socio = null;
            Entity Movim = null;
            Entity Socio_Act = null;

            /*Recuperamos los datos de Importes del Socio en cuestión */
            if (Tipo.Equals(Socios.Plus))
                Socio = Servicio.Retrieve("contact", SocioId, new ColumnSet("gfa_importetotalacumulaciones", "gfa_importetotalredenciones"));
            else
                Socio = Servicio.Retrieve("account", SocioId, new ColumnSet("gfa_importetotalacumulaciones", "gfa_importetotalredenciones"));

            // Recuperamos los importes que se tienen hasta el momento en el socio
            if (MetodosFes.ExisteAtributo("gfa_importetotalacumulaciones", Socio))
                TotalAcum = ((Money)Socio.Attributes["gfa_importetotalacumulaciones"]).Value;

            if (MetodosFes.ExisteAtributo("gfa_importetotalredenciones", Socio))
                TotalRed = ((Money)Socio.Attributes["gfa_importetotalredenciones"]).Value;

            /* Recuperamos el importe de la acumulación o redención  */
            if (Mov.Equals(Movimiento.Acumulacion))
                Movim = Servicio.Retrieve("gfa_acumulacionkm", IdMov, new ColumnSet("gfa_importeservicio", "statecode"));

            if (Mov.Equals(Movimiento.Redencion))
                Movim = Servicio.Retrieve("gfa_redencionkm", IdMov, new ColumnSet("gfa_importeservicio", "statecode"));

            // Asignamos el dato
            if (MetodosFes.ExisteAtributo("statecode", Movim))
                // Validamos que el registro esté activo
                if (((OptionSetValue)Movim.Attributes["statecode"]).Value.Equals(0))
                    ImporteServ = ((Money)Movim.Attributes["gfa_importeservicio"]).Value;

            /*Sumamos los importes del servicio del movimiento con los acumulados por el Socio (encabezado)*/
            if (Mov.Equals(Movimiento.Acumulacion))
                TotalAcum = TotalAcum + ImporteServ;

            // Si es cancelación de viaje, es necesario quitarle el importe de la acumulación
            if (Mov.Equals(Movimiento.CancelacionViaje))
                TotalAcum = TotalAcum - ImporteServ;

            if (Mov.Equals(Movimiento.Redencion))
                TotalRed = TotalRed + ImporteServ;


            /* Actualizamos los importes en el Socio*/
            /*Si es Socio Plus*/
            if (Tipo.Equals(Socios.Plus))
            {
                Socio_Act = new Entity("contact");
                Socio_Act.Attributes["contactid"] = SocioId;
            }
            else
            {
                Socio_Act = new Entity("account");
                Socio_Act.Attributes["accountid"] = SocioId;
            }
            /*Se valida si existen totales para ser actualizados */
            if (TotalAcum >= 0)
                Socio_Act.Attributes["gfa_importetotalacumulaciones"] = new Money(TotalAcum);
            if (TotalRed >= 0)
                Socio_Act.Attributes["gfa_importetotalredenciones"] = new Money(TotalRed);

            // Ejecutamos la actualización
            Servicio.Update(Socio_Act);
        }


        #endregion

        #region # **** SobreCargado Método para calcular Importe Total Kilómetros Extra
        public static void CalculaTotalImportes(Socios Soc, Guid SocioId, Movimiento Mov, string ClaveCompra)
        {
            OptionSetValue ImporteOp;
            string ImporteTxt = string.Empty;
            decimal TotalExt = 0;

            EntityCollection Resultados = null;

            /*Recuperamos el Guid de la Justificación de Movimiento como Kilómetros Extra */
            Guid IdJustMovCompra = RecuperaGuidJustMov(ClaveCompra);

            if (IdJustMovCompra != Guid.Empty)
            {
                /*Recuperamos todas los Kilómetros Extra con Justificación de Movimiento: Compra de Kilometros    */
                if (Mov.Equals(Movimiento.KmExtra))
                {
                    if (Soc.Equals(Socios.Plus))
                        Resultados = RecuperacionMultiple("gfa_extrakm", new string[] { "gfa_importeporkm" }, "statecode", "Active", "gfa_socioid", SocioId.ToString(), "gfa_justificaciondemovimientoid", IdJustMovCompra.ToString());
                    else
                        Resultados = RecuperacionMultiple("gfa_extrakm", new string[] { "gfa_importeporkm" }, "statecode", "Active", "gfa_empresaid", SocioId.ToString(), "gfa_justificaciondemovimientoid", IdJustMovCompra.ToString());
                }


                /* Sumamos todos los importes   */
                if (Resultados != null)
                {
                    if (Resultados.Entities.Count > 0)
                    {
                        foreach (Entity Res in Resultados.Entities)
                        {
                            if (ExisteAtributo("gfa_importeporkm", Res))
                            {
                                ImporteOp = (OptionSetValue)Res.Attributes["gfa_importeporkm"];
                                /*Recuperamos el valor de texto de la opción */
                                ImporteTxt = RecuperaOpcionListaTexto("gfa_extrakm", "gfa_importeporkm", ImporteOp);
                                /*Recuperamos el valor númerico de la opción  y realizamos la suma */
                                TotalExt += Convert.ToDecimal(ImporteTxt.Substring(1, ImporteTxt.Length - 1));
                            }
                        }
                    }
                }
            }

            Entity Socio_Act = null;
            /* Actualizamos los importes en el Socio*/
            /*Si es Socio Plus*/
            if (Soc.Equals(Socios.Plus))
            {
                Socio_Act = new Entity("contact");
                Socio_Act.Attributes["contactid"] = SocioId;
            }
            else
            {
                Socio_Act = new Entity("account");
                Socio_Act.Attributes["accountid"] = SocioId;
            }

            Socio_Act.Attributes["gfa_importetotalcomprakm"] = new Money(TotalExt);
            Servicio.Update(Socio_Act);
        }
        #endregion

        #region # ***** Recuperar Medio de por el Usuario que ejecuta el plugin
        public static Guid RecuperaGuidMedioporArea(int AreaVal)
        {
            Guid MedId = Guid.Empty;

            /*Colocamos el tipo de Medio en base al área*/
            /*Call Center */
            if (AreaVal.Equals(223060000))
                MedId = RecuperaGuidMedio("CC");

            /*Servicio al Cliente  */
            if (AreaVal.Equals(223060001))
                MedId = RecuperaGuidMedio("SC");

            /*Siempre Plus  */
            if (AreaVal.Equals(223060002))
                MedId = RecuperaGuidMedio("SP");

            /*Socios de Negocio  */
            if (AreaVal.Equals(223060003))
                MedId = RecuperaGuidMedio("SN");

            /*Marketing  */
            if (AreaVal.Equals(223060004))
                MedId = RecuperaGuidMedio("MK");

            /*Redes Sociales  */
            if (AreaVal.Equals(223060005))
                MedId = RecuperaGuidMedio("RS");

            /*Estudios de Mercado  */
            if (AreaVal.Equals(223060006))
                MedId = RecuperaGuidMedio("EM");

            return MedId;
        }
        #endregion

        #region # ***** Método para registrar el historial de cambios del Socio
        public static void CreaHistorial(string Nombre, string motivo, int edoSocio, Guid IdSoc, Guid IdUsr, bool esplus)
        {

            /*Creamos el objeto del registro del historial */
            Entity Hist = new Entity("gfa_historicoestados");

            if (Nombre != string.Empty)
                Hist.Attributes["gfa_nombre"] = Nombre.ToUpper() + " " + DateTime.Now.ToLocalTime().ToString("dd/MM/yyyy");
            else
                Hist.Attributes["gfa_nombre"] = "NO EXISTE NOMBRE DE ESTADO PARA HISTORICO";

            if (IdSoc != Guid.Empty)
                if (esplus)
                    Hist.Attributes["gfa_socioid"] = new EntityReference("contact", IdSoc);
                else
                    Hist.Attributes["gfa_empresaid"] = new EntityReference("account", IdSoc);

            /* Realizamos la conversión del catálogo de estados entre Socio e Historial */
            if (MetodosFes.CatalogoHistorialCambios(edoSocio, esplus) != -1)
                Hist.Attributes["gfa_estado"] = new OptionSetValue(MetodosFes.CatalogoHistorialCambios(edoSocio, esplus));

            /*Recuperamos el valor del área del Usuario que realiza el cambio */
            if (IdUsr != Guid.Empty)
            {
                // El usuario que manda llamar el Plugin, es el que hace el cambio
                Hist.Attributes["gfa_usuarioid"] = new EntityReference("systemuser", IdUsr);
                // Recuperación del área a la que pertenece
                Entity Usr = Servicio.Retrieve("systemuser", IdUsr, new ColumnSet("gfa_area"));
                if (ExisteAtributo("gfa_area", Usr))              
                    Hist.Attributes["gfa_areacambio"] = new OptionSetValue(((OptionSetValue)Usr.Attributes["gfa_area"]).Value);                                    
            }

            if (motivo != string.Empty)
                Hist.Attributes["gfa_motivo"] = motivo;
            else
                Hist.Attributes["gfa_motivo"] = "NO SE CAPTURÓ UN MOTIVO PARA HISTORICO";

            Servicio.Create(Hist);

        }
        #endregion

        #region # ***** Método para obtener el catálogo de Estados del Socio en Historial de Cambios
        public static int CatalogoHistorialCambios(int EdoSocio, bool socplus)
        {
            int edohist = -1;

            if (socplus)
            {
                switch (EdoSocio)
                {
                    // PENDIENTE DE VALIDACION
                    case 1: edohist = 223060000;
                        break;
                    // ALTA 
                    case 223060003: edohist = 223060001;
                        break;
                    // ALTA POR CAMBIO DE TIPO
                    case 223060002: edohist = 223060002;
                        break;
                    // ALTA POR DESBLOQUEO
                    case 223060005: edohist = 223060003;
                        break;
                    // ALTA POR REACTIVACION
                    case 223060006: edohist = 223060004;
                        break;
                    // BLOQUEADO
                    case 2: edohist = 223060005;
                        break;
                    // EN BAJA
                    case 223060004: edohist = 223060006;
                        break;
                }
            }
            else  // para cuando el Socio es una Empresa
            {
                switch (EdoSocio)
                {
                    // PENDIENTE DE VALIDACION
                    case 1: edohist = 223060000;
                        break;

                    // ALTA
                    case 223060000: edohist = 223060001;
                        break;
                    // ALTA POR DESBLOQUEO
                    case 223060001: edohist = 223060003;
                        break;
                    // ALTA POR REACTIVACION
                    case 223060004: edohist = 223060004;
                        break;
                    // BLOQUEADO
                    case 2: edohist = 223060005;
                        break;
                    // EN BAJA
                    case 223060003: edohist = 223060006;
                        break;
                }
            }



            return edohist;
        }

        #endregion

        #region # ***** Método para validar si es Socio Corporativo "CO"
        public static bool EsTipoSocioCorporativo(Entity SC)
        {
            Entity TipoSocio = null;
            bool EsCo = false;

            // Recuperamos el Guid del Tipo de Socio 
            if (MetodosFes.ExisteAtributo("gfa_tipodesocioid", SC))
            {
                // Recuperamos la Clave del Tipo de Socio, si es "CO", hacemos el proceso
                TipoSocio = Servicio.Retrieve("gfa_tiposocios", ((EntityReference)SC.Attributes["gfa_tipodesocioid"]).Id, new ColumnSet("gfa_id"));
                if (MetodosFes.ExisteAtributo("gfa_id", TipoSocio))
                {
                    if (((string)TipoSocio.Attributes["gfa_id"]).Equals("CO"))
                        EsCo = true;
                }
            }

            return EsCo;
        }
        #endregion

        #region ***  Método para validar Horas en Integración (23:59)
        public static bool ValidaHorasIntegra(string dato)
        {
            int Idx = -1;
            bool EsValido = false;
            int hora = 0;
            int mins = 0;

            if (dato.Length.Equals(5))
            {
                Idx = dato.IndexOf(':');
                if (Idx > 0)
                {
                    if (dato.Split(':').Length.Equals(2))
                    {
                        hora = Convert.ToInt32(dato.Split(':')[0]);
                        mins = Convert.ToInt32(dato.Split(':')[1]);

                        EsValido = (hora >= 0 && hora < 24) ? true : false;
                        EsValido = (mins >= 0 && mins < 60) ? true : false;
                    }
                }
            }
            return EsValido;
        }
        #endregion

        #region  ***  Método para validar Asiento
        public static bool ValidaAsientoIntegra(string dato)
        {
            bool EsValido = true;

            if (dato.Length > 0 && dato.Length < 3)
            {
                if (Convert.ToInt32(dato) > 50)
                {
                    EsValido = false;
                }
            }
            else
                EsValido = false;

            return EsValido;
        }
        #endregion

        #region  ***  Método para Agregar a una lista todos los movimientos que tiene el Socio se usa para BAJAS
        public static List<ListaBorrar> GeneraListaUltMovsBorrar(Guid IdSocio, bool EsPlus)
        {
            /*Recuperamos los ultimos movimientos(Actualizacion de Datos, Acumulaciones, Redenciones, Cancelaciones, Kilometros Extra)*/
            List<ListaBorrar> ParaBorrarMovs = new List<ListaBorrar>();
            // Limpiamos el objeto de la lista
            ParaBorrarMovs.Clear();

            string CampoSocioEmpresa = string.Empty;
            // Si es Plus o Empresa, el campo lógico cambia para se usado en la consulta
            CampoSocioEmpresa = (EsPlus) ? "gfa_socioid" : "gfa_empresaid";

            int indice = 0;
            /*Columnas de atributos a recuperar */
            string[] ColumnasAct = new string[] { "gfa_actualizaciondatosid", "gfa_name" };
            string[] ColumnasAcum = new string[] { "gfa_acumulacionkmid", "gfa_name" };
            string[] ColumnasRed = new string[] { "gfa_redencionkmid", "gfa_name" };
            string[] ColumnasCanc = new string[] { "gfa_cancelacionkmid", "gfa_name" };
            string[] ColumnasKmEx = new string[] { "gfa_extrakmid", "gfa_name" };

            /*Definimos la coleccion de datos de respuesta */
            EntityCollection Regs = null;
            /* Recuperamos los Registros del Socio de ACTUALIZACION DE DATOS  */
            /*Aquellos registros del Socio Activos y ordenados de manera ascendente por la fecha de creación*/
            Regs = MetodosFes.RecuperacionMultiple("gfa_actualizaciondatos", ColumnasAct, "statecode", "Inactive", CampoSocioEmpresa, IdSocio.ToString(), "createdon");

            if (Regs.Entities.Count() > 0)
            {
                foreach (Entity Mov in Regs.Entities)
                {
                    if (MetodosFes.ExisteAtributo("gfa_actualizaciondatosid", Mov) && indice != 0)
                        ParaBorrarMovs.Add(new ListaBorrar { Entidad = "gfa_actualizaciondatos", Id = (Guid)Mov.Attributes["gfa_actualizaciondatosid"] });

                    indice++;
                }
            }

            /* Recuperamos los Registros del Socio de ACUMULACION DE KM  */
            // Si es Socio Corporativo, no agregamos a la lista de borrado las acumulaciones, debido a que éste Socio no realiza acreditaciones
            if (EsPlus)
            {
                Regs = null;
                indice = 0;
                Regs = MetodosFes.RecuperacionMultiple("gfa_acumulacionkm", ColumnasAcum, "statecode", "Active", CampoSocioEmpresa, IdSocio.ToString(), "createdon");

                if (Regs.Entities.Count() > 0)
                {
                    foreach (Entity Mov in Regs.Entities)
                    {
                        if (MetodosFes.ExisteAtributo("gfa_acumulacionkmid", Mov) && indice != 0)
                            ParaBorrarMovs.Add(new ListaBorrar { Entidad = "gfa_acumulacionkm", Id = (Guid)Mov.Attributes["gfa_acumulacionkmid"] });

                        indice++;
                    }
                }
            }
        

            /* Recuperamos los Registros del Socio de REDENCION DE KM  */
            Regs = null;
            indice = 0;
            Regs = MetodosFes.RecuperacionMultiple("gfa_redencionkm", ColumnasRed, "statecode", "Active", CampoSocioEmpresa, IdSocio.ToString(), "createdon");

            if (Regs.Entities.Count() > 0)
            {
                foreach (Entity Mov in Regs.Entities)
                {
                    if (MetodosFes.ExisteAtributo("gfa_redencionkmid", Mov) && indice != 0)
                        ParaBorrarMovs.Add(new ListaBorrar { Entidad = "gfa_redencionkm", Id = (Guid)Mov.Attributes["gfa_redencionkmid"] });

                    indice++;
                }
            }

            /* Recuperamos los Registros del Socio de CANCELACION DE REDENCIONES  */
            Regs = null;
            indice = 0;
            Regs = MetodosFes.RecuperacionMultiple("gfa_cancelacionkm", ColumnasCanc, "statecode", "Inactive", CampoSocioEmpresa, IdSocio.ToString(), "createdon");

            if (Regs.Entities.Count() > 0)
            {
                foreach (Entity Mov in Regs.Entities)
                {
                    if (MetodosFes.ExisteAtributo("gfa_cancelacionkmid", Mov) && indice != 0)
                        ParaBorrarMovs.Add(new ListaBorrar { Entidad = "gfa_cancelacionkm", Id = (Guid)Mov.Attributes["gfa_cancelacionkmid"] });

                    indice++;
                }
            }

            /* Recuperamos los Registros del Socio de KM EXTRA */
            Regs = null;
            indice = 0;
            Regs = MetodosFes.RecuperacionMultiple("gfa_extrakm", ColumnasKmEx, "statecode", "Inactive", CampoSocioEmpresa, IdSocio.ToString(), "createdon");

            if (Regs.Entities.Count() > 0)
            {
                foreach (Entity Mov in Regs.Entities)
                {
                    if (MetodosFes.ExisteAtributo("gfa_extrakmid", Mov) && indice != 0)
                        ParaBorrarMovs.Add(new ListaBorrar { Entidad = "gfa_extrakm", Id = (Guid)Mov.Attributes["gfa_extrakmid"] });

                    indice++;
                }
            }

            return ParaBorrarMovs;
        }
        #endregion

        #region # **** Método para crear una redención genérica por baja
        public static Entity CreaObjRedencionPorBaja(int KmDisp, Guid IdSocio, bool EsPlus)
        {
            Guid OrigDestGenId = Guid.Empty;
            Guid OficinaGenId = Guid.Empty;
            Guid TipoRedGenId = Guid.Empty;

            /*Recuperamos Origen Destino Generico */
            OrigDestGenId = MetodosFes.RecuperaGuidOrgDest("ON - ON"); // Origen Destino generico
            /*Recuperamos Oficina SP */
            OficinaGenId = MetodosFes.RecuperaGuidOficina("SP");          

            /*Genera Redención que consuma Kms*/
            Entity RedencionBaja = new Entity("gfa_redencionkm");
            /*Se setean Nombre de la Redencion */
            RedencionBaja.Attributes["gfa_name"] = "0000 - REDENCION POR EXPIRACION DE KILOMETROS";
            /*Se setean Kms Disponibles igual a Kms usados*/
            RedencionBaja.Attributes["gfa_kmusados"] = KmDisp;

            /*Se setea Socio relacionado a la redencion, dependiendo si es Plus o Corporativo*/
            if (EsPlus)
                RedencionBaja.Attributes["gfa_socioid"] = new EntityReference("contact", IdSocio);
            else
                RedencionBaja.Attributes["gfa_empresaid"] = new EntityReference("account", IdSocio);

            /*Fecha de redención */
            RedencionBaja.Attributes["gfa_fecharedencion"] = DateTime.Now.ToLocalTime();
            /*Fecha de servicio */
            RedencionBaja.Attributes["gfa_fechaservicio"] = DateTime.Now.ToLocalTime();
            RedencionBaja.Attributes["gfa_horaservicio"] = "00:00";
            RedencionBaja.Attributes["gfa_asiento"] = 0;
            RedencionBaja.Attributes["gfa_numredencion"] = "SP0000";
            RedencionBaja.Attributes["gfa_numerooperacion"] = "0000";
            RedencionBaja.Attributes["gfa_importeservicio"] = new Money(0);
            RedencionBaja.Attributes["gfa_fecharedencion"] = DateTime.Now.ToLocalTime();
            RedencionBaja.Attributes["gfa_claveexpendedor"] = "SP";
            RedencionBaja.Attributes["gfa_numerodeservicio"] = "N/A";

            if (OficinaGenId != Guid.Empty)
                RedencionBaja.Attributes["gfa_oficinaid"] = new EntityReference("gfa_catalogo_ofdest_sp", OficinaGenId);          

            if (OrigDestGenId != Guid.Empty)
                RedencionBaja.Attributes["gfa_origendestinoid"] = new EntityReference("gfa_catalogoorigendestino", OrigDestGenId);

            if (RecuperaGuidMedio("SP") != Guid.Empty)
                RedencionBaja.Attributes["gfa_medioid"] = new EntityReference("gfa_catalogodemedios", RecuperaGuidMedio("SP"));

            if (RecuperaGuidJustMov("CRE") != Guid.Empty)
                /*Se setea Justificación de Movimiento como  CRE: Redencion por expiracion de Kms*/
                RedencionBaja.Attributes["gfa_justificaciondemovimientoid"] = new EntityReference("gfa_justmov", RecuperaGuidJustMov("CRE"));

            return RedencionBaja;
        }
        #endregion

    }
}
